package cn.org.seventh.common;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 常用字符串相关工具类
 * 没有commons utils齐全，如有需要参考该开源项目
 * @author <a href="mailto:ji.li@symbio-group.com">Andy</a>
 * @since Nov 30, 2007 4:17:48 PM
 */
public final class StringUtil {

	private static Log log = LogFactory.getLog(StringUtil.class);

	private final static String AS = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";

	/**
	 * Encode a string using algorithm specified in web.xml and return the
	 * resulting encrypted password. If exception, the plain credentials string
	 * is returned
	 * 
	 * @param password
	 *            Password or other credentials to use in authenticating this
	 *            username
	 * @param algorithm
	 *            Algorithm used to do the digest
	 * @return encypted password based on the algorithm.
	 */
	public static String encodePassword(String password, String algorithm) {
		byte[] unencodedPassword = password.getBytes();
		MessageDigest md = null;
		try {
			// first create an instance, given the provider
			md = MessageDigest.getInstance(algorithm);
		} catch (Exception e) {
			log.error("Exception: " + e);
			return password;
		}
		md.reset();
		// call the update method one or more times
		// (useful when you don't know the size of your data, eg. stream)
		md.update(unencodedPassword);
		// now calculate the hash
		byte[] encodedPassword = md.digest();
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < encodedPassword.length; i++) {
			if ((encodedPassword[i] & 0xff) < 0x10) {
				buf.append("0");
			}
			buf.append(Long.toString(encodedPassword[i] & 0xff, 16));
		}
		return buf.toString();
	}

	/**
	 * Encode a string using Base64 encoding. Used when storing passwords as
	 * cookies. This is weak encoding in that anyone can use the decodeString
	 * routine to reverse the encoding.
	 * 
	 * @param str
	 * @return String
	 */
	public static String encodeString(String str) {
		org.w3c.tools.codec.Base64Encoder encoder = new org.w3c.tools.codec.Base64Encoder(
				str);
		return encoder.processString();
	}

	/**
	 * Decode a string using Base64 encoding.
	 * 
	 * @param str
	 * @return String
	 */
	public static String decodeString(String str) {
		org.w3c.tools.codec.Base64Decoder dec = new org.w3c.tools.codec.Base64Decoder(
				str);
		try {
			return dec.processString();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static boolean isEmpty(String s) {
		return s == null || s.trim().length() == 0;
	}

	/**
	 * Replace the old sub string with new sub string in a string
	 * 
	 * @param s
	 *            a <code>String</code> value
	 * @param o
	 *            a <code>String</code> value
	 * @param n
	 *            a <code>String</code> value
	 * @return a <code>String</code> value
	 */
	public static String replace(String s, String o, String n) {
		if (s == null) {
			return null;
		}
		if (o == null || n == null) {
			throw new IllegalArgumentException(
					"The old str or the new str is null!");
		}
		StringBuffer sb = new StringBuffer();
		int start = -1;
		int end = 0;
		while ((start = s.indexOf(o, end)) != -1) {
			sb.append(s.substring(end, start));
			sb.append(n);
			end = start + o.length();
		}
		if (end <= s.length() - 1) {
			sb.append(s.substring(end));
		}
		return sb.toString();
	}

	/**
	 * Convert the plain text to html.
	 * 
	 * @param s
	 *            a <code>String</code> value
	 * @return a <code>String</code> value
	 */
	public static String toHtml(String s) {
		if (s == null) {
			return null;
		}
		String r = replace(s, "\r", "");
		r = replace(r, "&lt;", "<");
		r = replace(r, "&gt;", ">");
		return r;
	}

	public static String removeSpaces(String src) {
		return replace(src, " ", "");
	}

	public static String html2Text(String str) {
		if (str == null) {
			return null;
		}
		String tag = "";
		String result = "";
		String str2 = "";
		String l = "<";
		String r = ">";
		int offset1 = -1;
		int offset2 = -1;
		String temp = "";
		str2 = str;
		do {
			offset1 = str2.indexOf(l);
			offset2 = str2.indexOf(r);
			if (offset1 > 0) {
				temp = str2.substring(0, offset1);
				result += temp;
				str2 = str2.substring(offset1, str2.length());
				continue;
			}
			if (offset1 == -1) {
				result += str2;
				break;
			}
			tag = str2.substring(offset1 + 1, offset2);
			str2 = str2.substring(offset2 + 1, str2.length());
			tag.toLowerCase();
			if ("br".equalsIgnoreCase(tag)) {
				result += "\r\n";
			} else {
				tag = "";
			}
		} while (true);
		while (result.indexOf("&nbsp;") != -1)
			result = replace(result, "&nbsp;", " ");
		return result;
	}

	public static String limitString(String s, int byteLength) {
		return limitString(s, byteLength, null);
	}

	public static String limitString(String s, int byteLength, String omit) {
		if (s == null) {
			return null;
		}
		if (byteLength <= 0) {
			return "";
		}
		if (s.getBytes().length <= byteLength) {
			return s;
		}
		String r = "";
		int omitLength = 0;
		if (omit != null) {
			omitLength = omit.length();
		}
		for (int i = 0; i < s.length(); i++) {
			String tmp = s.substring(i, i + 1);
			if (r.getBytes().length + tmp.getBytes().length > byteLength
					- omitLength) {
				break;
			}
			r += tmp;
		}
		if (omit != null) {
			r += omit;
		}
		return r;
	}

	public static String createVerifyCode() {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 4; i++) {
			char c = AS.charAt((int) (Math.random() * (AS.length())));
			sb.append(c);
		}
		return sb.toString().toUpperCase();
	}

	public static String trim(String s) {
		if (s == null) {
			return null;
		}
		return s.trim();
	}

	public static String toSize(String s, int byteLength, String omit) {
		if (byteLength <= 0) {
			return "";
		}
		if (s == null) {
			s = "";
		}
		if (omit == null) {
			omit = "...";
		}
		int omitSize = omit.getBytes().length;
		if (s.getBytes().length > byteLength) {
			if (byteLength < omitSize) {
				s = limitString(s, byteLength);
			} else {
				s = limitString(s, byteLength - omitSize, omit);
			}
		}
		while (s.getBytes().length + omitSize <= byteLength) {
			s += omit;
		}
		return s;
	}

	/**
	 * Convert List To Set.
	 * 
	 * @param list
	 * @return the Set result.
	 */
	public static Set convertListToSet(List list) {
		Set set = new HashSet();
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				if (list.get(i) != null) {
					set.add(list.get(i));
				}
			}
		}
		return set;
	}

	/**
	 * Convert String To List.
	 * 
	 * @param str
	 * @param split
	 * @return the List result.
	 */
	public static List convertStringToList(String str, String split) {
		List list = new ArrayList();
		if (str != null && str.length() > 0) {
			String[] arr = str.split(split, -1);
			for (int i = 0; i < arr.length; i++) {
				String item = arr[i];
				list.add(i, item);
			}
		}
		return list;
	}

	/**
	 * convert IP Address To Number.
	 * 
	 * @param ip
	 * @return
	 * @throws Exception
	 */
	public static Long convertIpToNumber(String ip) throws Exception {
		InetAddress address = InetAddress.getByName(ip.trim());
		byte[] bs = address.getAddress();
		int a = bs[0] < 0 ? 256 + bs[0] : bs[0];
		a <<= 24;
		int b = bs[1] < 0 ? 256 + bs[1] : bs[1];
		b <<= 16;
		int c = bs[2] < 0 ? 256 + bs[2] : bs[2];
		c <<= 8;
		int d = bs[3] < 0 ? 256 + bs[3] : bs[3];
		d <<= 0;
		Long number = Long.valueOf(a + b + c + d);
		return number;
	}

	public static String objectToString(Serializable serializable) {
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		ObjectOutputStream objectOutputStream = null;
		try {
			objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
			objectOutputStream.writeObject(serializable);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				objectOutputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			objectOutputStream = null;
		}
		byte[] bs = byteArrayOutputStream.toByteArray();
		// Deflater compresser = new Deflater();
		// compresser.setInput(bs);
		// compresser.setLevel(Deflater.BEST_COMPRESSION);
		// compresser.finish();
		// byte[] temp = new byte[bs.length];
		// int compressedDataLength = compresser.deflate(temp);
		// byte[] temp2 = new byte[compressedDataLength];
		// compresser.deflate(temp2);
		// DeflaterOutputStream deflaterOutputStream =
		// new DeflaterOutputStream(byteArrayOutputStream, compresser);
		// try {
		// deflaterOutputStream.finish();
		// } catch (Exception e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// } finally {
		// try {
		// deflaterOutputStream.close();
		// } catch (Exception e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		// deflaterOutputStream = null;
		// }
		// byte[] bss = byteArrayOutputStream.toByteArray();
		if (null != bs) {
			try {
				return encodeString(new String(bs, "ISO-8859-1"));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public static Object stringToObject(String string) {
		String str = decodeString(string);
		byte[] bs = null;
		try {
			bs = str.getBytes("ISO-8859-1");
		} catch (Exception e) {
			e.printStackTrace();
		}
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bs);
		ObjectInputStream objectInputStream = null;
		Object object = null;
		try {
			objectInputStream = new ObjectInputStream(byteArrayInputStream);
			object = objectInputStream.readObject();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				objectInputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			objectInputStream = null;
		}
		return object;
	}
}
